﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Profile;
using System.Configuration;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Logging;
using StructureMap;

namespace Medianamik.Core.Profile
{
    //Voir http://msdn.microsoft.com/en-us/library/ta63b872(VS.80).aspx
    //Pour un exemple d'implementation
    public class MedianamikProfileProvider : ProfileProvider
    {
        private ILogger _logger;
        private ILogger Logger
        {
            get
            {
                return _logger
                    ?? (_logger = new ObjectFactory<ILogger>().Get("MedianamikProfileProviderLogger"));
            }
        }

        private IUserProfileResolver _userProfileResolver;
        public IUserProfileResolver UserProfileResolver
        {
            get
            {
                return _userProfileResolver ??
                    (_userProfileResolver = ObjectFactory.GetInstance<IUserProfileResolver>());
            }
        }

        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate)
        {
            throw new NotImplementedException();
        }

        public override int DeleteProfiles(string[] usernames)
        {
            int counter = 0;

            var userIds = usernames.Select(n => DALProviderManager.DALProvider.SecurityDALProvider.GetUser(n))
                .Select(u => (object)u.UserId.ToString());

            var p = new Param(MedianamikProperties.ProfileUser, userIds.ToArray());

            var profiles = NodeManager.GetNodes<ProfileNode>(p, MedianamikTypes.MedianamikProfile);

            foreach (var profile in profiles)
            {
                NodeManager.DestroyNode(profile.InnerNode);
                counter++;
            }

            return counter;
        }

        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {
            var usernames = profiles.Cast<ProfileInfo>().Select(p => p.UserName).ToArray();
            return DeleteProfiles(usernames);
        }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption,
            string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize,
            out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption,
            string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption,
            int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate)
        {
            throw new NotImplementedException();
        }

        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context,
            SettingsPropertyCollection pProperties)
        {
            var values = new SettingsPropertyValueCollection();

            var username = (string)context["UserName"];
            var profile = GetProfileOrAnonymousProfile(username);

            foreach (SettingsProperty property in pProperties)
            {
                if (property.SerializeAs == SettingsSerializeAs.ProviderSpecific)
                    if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string))
                        property.SerializeAs = SettingsSerializeAs.String;
                    else
                        property.SerializeAs = SettingsSerializeAs.Xml;

                var value = new SettingsPropertyValue(property);

                if (!value.Name.Equals("NodeId") && !profile.DefaultInstance.Properties.Exists(value.Name))
                {
                    Logger.Warn("Profile Property '" + value.Name + "' does not exists on ProfileNode");
                    continue;
                }

                if (value.Name.Equals("NodeId")) // Récupérer le nodeid du PROFILE
                    value.PropertyValue = profile.ID;
                else if (value.Name.Equals("User")) // Récupérer le USERID GUID 
                    value.PropertyValue = profile.DefaultInstance.Properties["User"].Value;
                else
                    value.PropertyValue = profile.DefaultInstance.Properties[value.Name].GetValue();

                value.IsDirty = false;
                values.Add(value);
            }

            return values;
        }

        private ProfileNode GetProfileOrAnonymousProfile(string username)
        {
            ProfileNode profile = null;
            if (!String.IsNullOrEmpty(username))
                profile = GetProfile(username);

            if (profile == null)
            {
                profile = NodeManager.NewNode<ProfileNode>(CultureInfo.InvariantCulture,
                                                           MedianamikModules.SecurityManagement);
                profile.UserId = Guid.NewGuid();
            }
            return profile;
        }

        public ProfileNode GetProfile(string username)
        {
            ProfileNode node;

            if (HttpContext.Current != null && HttpContext.Current.User.Identity.IsAuthenticated &&
                HttpContext.Current.User.Identity.Name.EqualsIgnoreCase(username))
            {
                node = HttpRuntime.Cache["CurrentUserProfile_" + username] as ProfileNode;

                if (node == null)
                {
                    node = GetProfileFromDB(username);

                    if (node != null)
                    {
                        HttpRuntime.Cache.Insert("CurrentUserProfile_" + username, node, null,
                                                 DateTime.MaxValue, new TimeSpan(0, 0, 10, 0));
                    }
                }
            }
            else
            {
                node = GetProfileFromDB(username);
            }

            return node;
        }

        public ProfileNode GetProfileFromDB(string username)
        {
            IUser user = null;

            try
            {
                user = DALProviderManager.DALProvider.SecurityDALProvider.GetUser(username);
            }
            catch (System.Data.SqlClient.SqlException ex)
            {
                //La connexion au provider TCP a été détruite. Réssayer.
                if (ex.Message.IndexOf("TCP Provider") > 0)
                    user = DALProviderManager.DALProvider.SecurityDALProvider.GetUser(username);
            }

            var userId = user == null ? Guid.NewGuid() : user.UserId;

            var profileNodeId = UserProfileResolver.GetUserProfileIdByUserId(userId);

            return profileNodeId.HasValue ? NodeManager.GetNode<ProfileNode>(profileNodeId.Value) : null;
        }

        public override void SetPropertyValues(SettingsContext context,
            SettingsPropertyValueCollection pValues)
        {
            var username = (string)context["UserName"];
            var profile = GetProfileOrAnonymousProfile(username);
            var mustSave = false;

            foreach (SettingsPropertyValue value in pValues)
            {
                if (!value.Property.Name.Equals("NodeId") &&
                    !value.Property.Name.Equals("User") &&
                    value.Property.PropertyType != typeof(IEnumerable<Guid>) &&
                    !value.Property.PropertyType.GetInterfaces().Any(x =>
                    x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<Guid>)))
                {
                    if (value.IsDirty)
                    {
                        var property = profile.DefaultInstance.Properties[value.Name];
                        property.SetValue(value.PropertyValue);
                        mustSave = true;
                    }
                }
            }

            if (mustSave)
            {
                if (profile[""].HasModifiedProperties && HttpContext.Current != null &&
                    HttpContext.Current.User.Identity.IsAuthenticated &&
                    HttpContext.Current.User.Identity.Name.EqualsIgnoreCase(profile.UserId.ToString()))
                {
                    HttpRuntime.Cache["CurrentUserProfile_" + username] = null;
                }

                NodeManager.SaveNode(profile);
            }
        }
    }
}